package com.gitee.wsl.android.ui.theme.inject

import android.R
import android.content.res.ColorStateList
import android.graphics.Color
import android.graphics.PorterDuff
import android.graphics.drawable.Drawable
import android.view.View
import com.gitee.wsl.android.ext.base.adjustOpacity
import com.gitee.wsl.android.ext.base.buildColorStateList
import com.gitee.wsl.common.ui.theme.ColorPaletteScheme
import com.gitee.wsl.common.ui.theme.ComposeColorPaletteScheme
import com.gitee.wsl.common.ui.theme.Theme
import com.gitee.wsl.common.ui.theme.TypographyScheme
import com.gitee.wsl.common.ui.theme.outlinedButtonStrokeWidth
import com.gitee.wsl.ext.base.ColorExt
import com.google.android.material.appbar.MaterialToolbar
import com.google.android.material.button.MaterialButton
import com.google.android.material.card.MaterialCardView
import com.google.android.material.chip.Chip
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.progressindicator.LinearProgressIndicator
import com.google.android.material.tabs.TabLayout
import com.google.android.material.textfield.TextInputLayout
import com.google.android.material.textview.MaterialTextView

object MaterialViewThemeInject {
    fun <P: ColorPaletteScheme,T: TypographyScheme,THEME: Theme<P,T>> injectTheme(theme:THEME, view: View):Boolean{
        when(view){
            is MaterialToolbar-> view.theme(theme)
            is FloatingActionButton -> view.theme(theme)
            is ExtendedFloatingActionButton -> view.theme(theme)
            is MaterialCardView -> view.theme(theme)
            is MaterialButton-> view.theme(theme)
            is Chip -> view.theme(theme)
            is TextInputLayout -> view.theme(theme)
            is TabLayout -> view.theme(theme)
            else-> return false
        }
        return true
    }
}


fun <P: ColorPaletteScheme,T: TypographyScheme,THEME: Theme<P, T>> MaterialToolbar.theme(theme:THEME, searchText: MaterialTextView? = null) {
    useTheme(this, theme.colorScheme.toAndroid()) { scheme ->
        overflowIcon?.colorTrailingIcon(theme)
        searchText?.setHintTextColor(scheme.onSurfaceVariant)
    }
}

fun <P: ColorPaletteScheme,T: TypographyScheme,THEME: Theme<P, T>> Drawable.colorTrailingIcon(theme:THEME) {
    useTheme(this, theme.colorScheme.toAndroid()) { scheme ->
        setColorFilter(scheme.onSurfaceVariant, PorterDuff.Mode.SRC_ATOP)
    }
}

fun <P: ColorPaletteScheme,T: TypographyScheme,THEME: Theme<P, T>> FloatingActionButton.theme(theme:THEME) {
    useTheme(this, theme.colorScheme.toAndroid()) { scheme ->
        backgroundTintList = ColorExt.buildColorStateList(
            R.attr.state_enabled to scheme.primaryContainer,
            -R.attr.state_enabled to Color.GRAY
        )

        imageTintList = ColorExt.buildColorStateList(
            R.attr.state_enabled to scheme.onPrimaryContainer,
            -R.attr.state_enabled to Color.WHITE
        )
    }
}

fun <P: ColorPaletteScheme,T: TypographyScheme,THEME: Theme<P, T>> ExtendedFloatingActionButton.theme(theme:THEME) {
    useTheme(this, theme.colorScheme.toAndroid()) { scheme ->
        backgroundTintList = ColorExt.buildColorStateList(
            R.attr.state_enabled to scheme.primaryContainer,
            -R.attr.state_enabled to Color.GRAY
        )

        val colorStateList = ColorExt.buildColorStateList(
            R.attr.state_enabled to scheme.onPrimaryContainer,
            -R.attr.state_enabled to Color.WHITE
        )
        setTextColor(colorStateList)
        iconTint = colorStateList
    }
}

fun <P: ColorPaletteScheme,T: TypographyScheme,THEME: Theme<P, T>> MaterialCardView.theme(theme:THEME) {
    useTheme(this, theme.colorScheme.toAndroid()) { scheme ->
        backgroundTintList = ColorStateList.valueOf(scheme.surface)
        setStrokeColor(
            ColorExt.buildColorStateList(
                R.attr.state_checked to scheme.primary,
                -R.attr.state_checked to scheme.outline
            )
        )
    }
}

fun <P: ColorPaletteScheme,T: TypographyScheme,THEME: Theme<P, T>> MaterialButton.theme(theme:THEME) {
    useTheme(this, theme.colorScheme.toAndroid()) { scheme ->
        rippleColor = rippleColor(scheme)

        val colorStateList = ColorExt.buildColorStateList(
            R.attr.state_enabled to scheme.primary,
            -R.attr.state_enabled to theme.colorScheme.textDisabled.toInt()
        )
        setTextColor(colorStateList)
        iconTint = colorStateList
    }
}

fun <P: ColorPaletteScheme,T: TypographyScheme,THEME: Theme<P, T>> MaterialButton.themePrimaryFilled(theme:THEME) {
    useTheme(this, theme.colorScheme.toAndroid()) { scheme ->
        backgroundTintList = ColorExt.buildColorStateList(
            R.attr.state_enabled to scheme.primary,
            -R.attr.state_enabled to ColorExt.adjustOpacity(
                scheme.onSurface,
                SURFACE_OPACITY_BUTTON_DISABLED
            )
        )

        val contentColorList = ColorExt.buildColorStateList(
            R.attr.state_enabled to scheme.onPrimary,
            -R.attr.state_enabled to ColorExt.adjustOpacity(
                scheme.onSurface,
                SURFACE_OPACITY_BUTTON_DISABLED
            )
        )

        setTextColor(contentColorList)
        iconTint = contentColorList
    }
}


fun <P: ColorPaletteScheme,T: TypographyScheme,THEME: Theme<P, T>> MaterialButton.themePrimaryTonal(theme:THEME) {
    useTheme(this, theme.colorScheme.toAndroid()) { scheme ->
        backgroundTintList = ColorExt.buildColorStateList(
            R.attr.state_enabled to scheme.secondaryContainer,
            -R.attr.state_enabled to ColorExt.adjustOpacity(
                scheme.onSurface,
                SURFACE_OPACITY_BUTTON_DISABLED
            ),
            -R.attr.state_hovered to scheme.onSecondaryContainer,
            -R.attr.state_focused to scheme.onSecondaryContainer,
            -R.attr.state_pressed to scheme.onSecondaryContainer
        )

        val contentColorList = ColorExt.buildColorStateList(
            R.attr.state_enabled to scheme.onSecondaryContainer,
            -R.attr.state_enabled to ColorExt.adjustOpacity(
                scheme.onSurface,
                ON_SURFACE_OPACITY_BUTTON_DISABLED
            ),
            -R.attr.state_hovered to scheme.onSecondaryContainer,
            -R.attr.state_focused to scheme.onSecondaryContainer,
            -R.attr.state_pressed to scheme.onSecondaryContainer
        )
        setTextColor(contentColorList)
        iconTint = contentColorList
    }
}

fun <P: ColorPaletteScheme,T: TypographyScheme,THEME: Theme<P, T>> MaterialButton.themePrimaryOutlined(theme:THEME) {
    useTheme(this, theme.colorScheme.toAndroid()) { scheme ->
        val contentColorList = ColorExt.buildColorStateList(
            R.attr.state_enabled to scheme.primary,
            -R.attr.state_enabled to ColorExt.adjustOpacity(
                scheme.onSurface,
                ON_SURFACE_OPACITY_BUTTON_DISABLED
            )
        )

        setTextColor(contentColorList)
        iconTint = contentColorList
        strokeColor = ColorExt.buildColorStateList(
            R.attr.state_enabled to scheme.outline,
            -R.attr.state_enabled to ColorExt.adjustOpacity(
                scheme.onSurface,
                ON_SURFACE_OPACITY_BUTTON_OUTLINE_DISABLED
            ),
            -R.attr.state_hovered to scheme.outline,
            -R.attr.state_focused to scheme.primary,
            -R.attr.state_pressed to scheme.outline
        )

        strokeWidth = theme.dimen.outlinedButtonStrokeWidth.toInt()
        rippleColor = rippleColor(scheme)
    }
}

fun <P: ColorPaletteScheme,T: TypographyScheme,THEME: Theme<P, T>> MaterialButton.themePrimaryBorderless(theme:THEME) {
    useTheme(this, theme.colorScheme.toAndroid()) { scheme ->
        val contentColorList = ColorExt.buildColorStateList(
            R.attr.state_enabled to scheme.primary,
            -R.attr.state_enabled to ColorExt.adjustOpacity(
                scheme.onSurface,
                ON_SURFACE_OPACITY_BUTTON_DISABLED
            )
        )

        setTextColor(contentColorList)
        iconTint = contentColorList
    }
}

fun <P: ColorPaletteScheme,T: TypographyScheme,THEME: Theme<P, T>> MaterialButton.themeFilledOnPrimary(theme:THEME) {
    useTheme(this, theme.colorScheme.toAndroid()) { scheme ->
        backgroundTintList = ColorExt.buildColorStateList(
            R.attr.state_enabled to scheme.onPrimary,
            -R.attr.state_enabled to ColorExt.adjustOpacity(
                scheme.surface,
                SURFACE_OPACITY_BUTTON_DISABLED
            ),
            -R.attr.state_hovered to scheme.onPrimary,
            -R.attr.state_focused to scheme.onPrimary,
            -R.attr.state_pressed to scheme.onPrimary
        )

        val contentColorList = ColorExt.buildColorStateList(
            R.attr.state_enabled to scheme.primary,
            -R.attr.state_enabled to ColorExt.adjustOpacity(
                scheme.primary,
                ON_SURFACE_OPACITY_BUTTON_DISABLED
            ),
            -R.attr.state_hovered to scheme.primary,
            -R.attr.state_focused to scheme.primary,
            -R.attr.state_pressed to scheme.primary
        )

        setTextColor(
            contentColorList
        )

        iconTint = contentColorList
    }
}

fun <P: ColorPaletteScheme,T: TypographyScheme,THEME: Theme<P, T>> MaterialButton.themeOutlinedOnPrimary(theme:THEME) {
    useTheme(this, theme.colorScheme.toAndroid()) { scheme ->
        backgroundTintList = ColorStateList.valueOf(Color.TRANSPARENT)
        val contentColorList = ColorExt.buildColorStateList(
            R.attr.state_enabled to scheme.onPrimary,
            -R.attr.state_enabled to ColorExt.adjustOpacity(
                scheme.onPrimary,
                ON_SURFACE_OPACITY_BUTTON_DISABLED
            )
        )

        setTextColor(contentColorList)
        iconTint = contentColorList
        strokeColor = contentColorList
        strokeWidth = theme.dimen.outlinedButtonStrokeWidth.toInt()
        rippleColor = rippleColor(scheme)
    }
}

fun <P: ColorPaletteScheme,T: TypographyScheme,THEME: Theme<P, T>> MaterialToolbar.theme(theme:THEME) {
    useTheme(this, theme.colorScheme.toAndroid()) { scheme ->
        setBackgroundColor(scheme.surface)
        setNavigationIconTint(scheme.onSurface)
        setTitleTextColor(scheme.onSurface)
        overflowIcon?.colorTrailingIcon(theme)
    }
}

fun <P: ColorPaletteScheme,T: TypographyScheme,THEME: Theme<P, T>> LinearProgressIndicator.theme(theme:THEME) {
    useTheme(this, theme.colorScheme.toAndroid()) { scheme ->
        setIndicatorColor(scheme.primary)
    }
}

fun <P: ColorPaletteScheme,T: TypographyScheme,THEME: Theme<P, T>> TextInputLayout.theme(theme:THEME) {
    useTheme(this, theme.colorScheme.toAndroid()) { scheme ->
        val errorColor = scheme.onSurfaceVariant

        val errorColorStateList = ColorExt.buildColorStateList(
            -R.attr.state_focused to errorColor,
            R.attr.state_focused to errorColor
        )

        val coloredColorStateList = ColorExt.buildColorStateList(
            -R.attr.state_focused to scheme.outline,
            R.attr.state_focused to scheme.primary
        )

        setBoxStrokeColorStateList(coloredColorStateList)
        setErrorIconTintList(errorColorStateList)
        setErrorTextColor(errorColorStateList)
        boxStrokeErrorColor = errorColorStateList
        defaultHintTextColor = coloredColorStateList

        editText?.highlightColor = scheme.primary
    }
}

fun <P: ColorPaletteScheme,T: TypographyScheme,THEME: Theme<P, T>> TextInputLayout.theme(theme:THEME, colorSelect:P.()->Int) {
    useTheme(this, theme.colorScheme.toAndroid()) { scheme ->
        val errorColor = scheme.error

        val selectColor = colorSelect(theme.colorScheme)

        val errorColorStateList = ColorExt.buildColorStateList(
            -R.attr.state_focused to errorColor,
            R.attr.state_focused to errorColor
        )

        val coloredColorStateList = ColorExt.buildColorStateList(
            -R.attr.state_focused to scheme.outline,
            R.attr.state_focused to selectColor
        )

        setBoxStrokeColorStateList(coloredColorStateList)
        setErrorIconTintList(errorColorStateList)
        setErrorTextColor(errorColorStateList)
        boxStrokeErrorColor = errorColorStateList
        defaultHintTextColor = coloredColorStateList

        editText?.highlightColor = selectColor
        setEndIconTintList(coloredColorStateList)
        setStartIconTintList(coloredColorStateList)
    }
}

fun <P: ColorPaletteScheme,T: TypographyScheme,THEME: Theme<P, T>> TabLayout.theme(theme:THEME, onSurface:Boolean=false) {
    useTheme(this, theme.colorScheme.toAndroid()) { scheme ->
        if(onSurface) setBackgroundColor(scheme.surface)
        setSelectedTabIndicatorColor(scheme.primary)
        val tabContentColors = ColorExt.buildColorStateList(
            R.attr.state_selected to scheme.primary,
            -R.attr.state_selected to scheme.secondary
        )

        tabTextColors = tabContentColors
        tabIconTint = tabContentColors
        tabRippleColor = rippleColor(scheme)
    }
}

fun <P: ColorPaletteScheme,T: TypographyScheme,THEME: Theme<P, T>> Chip.theme(theme:THEME) {
    useTheme(this, theme.colorScheme.toAndroid()) { scheme ->
        chipBackgroundColor = ColorStateList.valueOf(scheme.primary)
        setTextColor(scheme.onPrimary)
    }
}

fun <P: ColorPaletteScheme,T: TypographyScheme,THEME: Theme<P, T>> Chip.themeOutlined(theme:THEME, strokeWidth: Float) {
    useTheme(this, theme.colorScheme.toAndroid()) { scheme ->
        chipBackgroundColor = ColorStateList.valueOf(Color.TRANSPARENT)
        chipStrokeWidth = strokeWidth
        chipStrokeColor = ColorStateList.valueOf(scheme.primary)
        setTextColor(scheme.primary)
    }
}

fun <P: ColorPaletteScheme,T: TypographyScheme,THEME: Theme<P, T>> Chip.themeSuggestion(theme:THEME) {
    useTheme(this, theme.colorScheme.toAndroid()) { scheme ->
        chipStrokeColor = chipOutlineColorList(scheme)
        setTextColor(chipSuggestionInputTextColorList(scheme))
    }
}

fun <P: ColorPaletteScheme,T: TypographyScheme,THEME: Theme<P, T>> Chip.themeAssist(theme:THEME) {
    useTheme(this, theme.colorScheme.toAndroid()) { scheme ->
        val iconColors = ColorExt.buildColorStateList(
            R.attr.state_enabled to scheme.primary,
            -R.attr.state_enabled to ColorExt.adjustOpacity(
                scheme.onSurface,
                ON_SURFACE_OPACITY_BUTTON_DISABLED
            ),
            R.attr.state_focused to scheme.primary,
            R.attr.state_hovered to scheme.primary,
            R.attr.state_pressed to scheme.primary
        )

        val textColors = ColorExt.buildColorStateList(
            R.attr.state_enabled to scheme.onSurface,
            -R.attr.state_enabled to ColorExt.adjustOpacity(
                scheme.onSurface,
                ON_SURFACE_OPACITY_BUTTON_DISABLED
            ),
            R.attr.state_hovered to scheme.onSurface,
            R.attr.state_focused to scheme.onSurface,
            R.attr.state_pressed to scheme.onSurface
        )

        chipStrokeColor = chipOutlineColorList(scheme)
        setTextColor(textColors)
        chipIconTint = iconColors
    }
}

fun <P: ColorPaletteScheme,T: TypographyScheme,THEME: Theme<P, T>> Chip.themeInput(theme:THEME) {
    useTheme(this, theme.colorScheme.toAndroid()) { scheme ->
        val iconColors = ColorExt.buildColorStateList(
            R.attr.state_enabled to scheme.onSurfaceVariant,
            -R.attr.state_enabled to ColorExt.adjustOpacity(
                scheme.onSurface,
                ON_SURFACE_OPACITY_BUTTON_DISABLED
            ),
            R.attr.state_focused to scheme.onSurfaceVariant,
            R.attr.state_hovered to scheme.onSurfaceVariant,
            R.attr.state_pressed to scheme.onSurfaceVariant
        )

        chipStrokeColor = chipOutlineColorList(scheme)
        setTextColor(chipSuggestionInputTextColorList(scheme))
        chipIconTint = iconColors
    }
}



private fun  <P: ComposeColorPaletteScheme<Int>> chipOutlineColorList(scheme: P) = ColorExt.buildColorStateList(
    android.R.attr.state_enabled to scheme.outline,
    -android.R.attr.state_enabled to ColorExt.adjustOpacity(
        scheme.onSurface,
        ON_SURFACE_OPACITY_BUTTON_OUTLINE_DISABLED
    ),
    android.R.attr.state_hovered to scheme.outline,
    android.R.attr.state_focused to scheme.onSurfaceVariant,
    android.R.attr.state_pressed to scheme.outline
)

private fun  <P: ComposeColorPaletteScheme<Int>> chipSuggestionInputTextColorList(scheme: P) = ColorExt.buildColorStateList(
    android.R.attr.state_enabled to scheme.onSurfaceVariant,
    -android.R.attr.state_enabled to ColorExt.adjustOpacity(
        scheme.onSurface,
        ON_SURFACE_OPACITY_BUTTON_DISABLED
    ),
    android.R.attr.state_hovered to scheme.onSurfaceVariant,
    android.R.attr.state_focused to scheme.onSurfaceVariant,
    android.R.attr.state_pressed to scheme.onSurfaceVariant
)


private fun <P: ComposeColorPaletteScheme<Int>> rippleColor(scheme: P) = ColorExt.buildColorStateList(
    android.R.attr.state_pressed to ColorExt.adjustOpacity(
        scheme.primary,
        SURFACE_OPACITY_BUTTON_DISABLED
    )
)

private const val SURFACE_OPACITY_BUTTON_DISABLED: Float = 0.12f
private const val ON_SURFACE_OPACITY_BUTTON_OUTLINE_DISABLED: Float = 0.12f
private const val ON_SURFACE_OPACITY_BUTTON_DISABLED: Float = 0.38f